package eerbaar.v2.app.view2;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import eerbaar.elements.extension.ILeaderElement;
import eerbaar.elements.extension.ILeaderListener;
import eerbaar.elements.extension.IPackMemberElement;
import eerbaar.elements.extension.IPackMemberListener;
import eerbaar.persona.IPersona;
import eerbaar.position.IPosition;
import eerbaar.v2.app.core.ISprite;

public class PersonaDisplayer {

    private static final int DELTA = 2;
    private static final int HEIGHT = 50;
    private static final int WIDTH = 50;

    private final IPersona persona;
    private final ImageStore store;

    private final Map<String, SlideImage> slideMap = new HashMap<String, SlideImage>();

    private Point start;
    private Point destination;
    private Point current;

    private final List<IPackLeaderDecorator> decorators = new ArrayList<IPackLeaderDecorator>();
    private IPackMemberDecorator memberDecorator;

    private boolean wasMoved;

    public PersonaDisplayer(ImageStore store, IPersona persona) {
        this.store = store;
        this.persona = persona;
        initDecorator();
    }

    private void addDecorator(IPackMemberElement member) {
        IPackLeaderDecorator d = findDecorator(member);
        if (d == null) {
            this.decorators.add(new PackLeaderDecorator(member));
        }
    }

    public void draw(Graphics2D g) {

        ISprite image = this.getImage();
        if (image == null) {
            return;
        }

        drawImage(g, image);
    }

    private void drawImage(Graphics2D g, ISprite image) {

        moveCurrentRect();
        if (this.wasMoved) {
            this.persona.setState(IPersona.State.ACTIVE);
        } else {
            this.persona.setState(IPersona.State.REST);
        }

        SlideImage slide = this.slideMap.get(image.toString());
        if (slide == null) {
            slide = new SlideImage(image);
            this.slideMap.put(image.toString(), slide);
        }

        Rectangle rect = new Rectangle(this.current, new Dimension(WIDTH,
                HEIGHT));
        slide.drawImage(rect, g);

        for (IPackLeaderDecorator d : this.decorators) {
            d.drawImage(rect, g);
        }
        if (this.memberDecorator != null) {
            this.memberDecorator.drawImage(rect, g);
        }
    }

    @Override
    public boolean equals(Object obj) {

        PersonaDisplayer other = (PersonaDisplayer) obj;
        return (this.persona == other.persona);
    }

    private IPackLeaderDecorator findDecorator(IPackMemberElement member) {

        IPackLeaderDecorator result = null;

        for (IPackLeaderDecorator d : this.decorators) {
            IPackMemberElement e = d.getPackMember();
            if (e == member) {
                this.decorators.remove(d);
                break;
            }
        }

        return result;
    }

    private ISprite getImage() {

        String name = this.persona.getName();
        IPersona.State state = this.persona.getState();
        IPersona.Direction direction = this.persona.getDirection();
        ImageId id = new ImageId(name, state, direction);

        return this.store.getImage(id);
    }

    public IPersona getPersona() {
        return this.persona;
    }

    private Point getPersonaRect() {

        IPosition p = this.persona.getPosition();
        int x = p.getX();
        int y = p.getY();
        return new Point(x * WIDTH, y * HEIGHT);
    }

    private void initDecorator() {

        {
            ILeaderListener listener = new ILeaderListener() {

                @Override
                public void onMemberAdded(IPackMemberElement member) {
                    PersonaDisplayer.this.addDecorator(member);
                }

                @Override
                public void onMemberRemove(IPackMemberElement member) {
                    PersonaDisplayer.this.removeDecorator(member);
                }

            };

            ILeaderElement leader = this.persona
                    .getExtension(ILeaderElement.class);
            if (leader != null) {
                leader.addListener(listener);
            }
        }

        {
            IPackMemberListener listener = new IPackMemberListener() {

                @Override
                public void onPackJoined() {
                    PersonaDisplayer.this.memberDecorator = new PackMemberDecorator();
                }

                @Override
                public void onPackLeft() {
                    PersonaDisplayer.this.memberDecorator = null;
                }

            };

            IPackMemberElement member = this.persona
                    .getExtension(IPackMemberElement.class);
            if (member != null) {
                member.addListener(listener);
            }
        }
    }

    private void moveCurrentRect() {

        Point rect = getPersonaRect();
        if (this.start == null) {
            this.start = rect;
            this.destination = rect;
        } else if (!this.destination.equals(rect)) {
            this.destination = rect;
        }

        if (this.current == null) {
            this.current = this.destination;
        }

        this.wasMoved = false;
        if (!this.current.equals(this.destination)) {

            this.wasMoved = true;

            int deltaX = 0;
            if (this.current.x < this.destination.x) {
                deltaX = DELTA;
            } else if (this.current.x > this.destination.x) {
                deltaX = -DELTA;
            }

            int deltaY = 0;
            if (this.current.y < this.destination.y) {
                deltaY = DELTA;
            } else if (this.current.y > this.destination.y) {
                deltaY = -DELTA;
            }

            this.current = new Point(this.current.x + deltaX, this.current.y
                    + deltaY);
        }
    }

    private void removeDecorator(IPackMemberElement member) {
        IPackLeaderDecorator d = findDecorator(member);
        if (d == null) {
            this.decorators.remove(d);
        }
    }

}
